﻿#region Copyright
/* © 2008 George Tsiokos, licensed under the Microsoft Reciprocal License (Ms-RL) */
#endregion
using System.Collections.Generic;
using System.Threading;
using System;
using Comet.Collections.Generic;

namespace Comet.ComponentModel {
    /// <summary>Experimental</summary>
    internal sealed class PersistedBus<T> : IBus<T> {

		#region Fields (5) 

        private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim (LockRecursionPolicy.NoRecursion);
        private volatile Semaphore _semaphore = CreateSemaphore ();
        private readonly TemporalList<T> _temporalList;

		#endregion Fields 

		#region Constructors (1) 

        public PersistedBus (TimeSpan timespan, int timespanCapacity) {
            _temporalList = new TemporalList<T> (timespan, timespanCapacity);
        }

		#endregion Constructors 

		#region Properties (3) 

        internal KeyValuePair<TemporalIndex, T> IndexAndValue {
            get {
                _lock.EnterReadLock ();
                KeyValuePair<TemporalIndex, T> value = _temporalList.IndexAndValue;
                _lock.ExitReadLock ();
                return value;
            }
        }

        public T Value {
            get {
                _lock.EnterReadLock ();
                T value = _temporalList.IndexAndValue.Value;
                _lock.ExitReadLock ();
                return value;
            }
        }

		#endregion Properties 

		#region Methods (5) 


		// Public Methods (3) 

        public IBusView<T> CreateView (bool includeHistory) {
            long startingIndex;
            if (includeHistory)
                startingIndex = 0;
            else {
                _lock.EnterReadLock ();
                startingIndex = _temporalList.GetTimestamp ();
                _lock.ExitReadLock ();
            }
            return new BusView<T> (this, startingIndex);
        }

        public void Publish (T value) {
            _lock.EnterWriteLock ();
            try {
                _temporalList.Add (value);
            }
            finally {
                _lock.ExitWriteLock ();
                using (Semaphore flag = _semaphore) {
                    _semaphore = CreateSemaphore ();
                    flag.Release (ComponentModelUtility.SemaphoreCount);
                }
            }
        }

        public WaitHandle Subscribe () {
            return _semaphore;
        }



		// Private Methods (1) 

        private static Semaphore CreateSemaphore () {
            return new Semaphore (0, ComponentModelUtility.SemaphoreCount);
        }



		// Internal Methods (1) 

        internal IEnumerable<T> GetFrom (MutableValueWrapper<TemporalIndex> counter) {
            _lock.EnterReadLock ();
            List<T> items;
            try {
                items = new List<T> (_temporalList.GetFrom (counter));
            }
            finally {
                _lock.ExitReadLock ();
            }
            return items;
        }

		#endregion Methods 

    }
}